package at.tugraz.hidipic.web.execution.impl;

import at.tugraz.hidipic.web.execution.DefaultMethodImpl;
import at.tugraz.hidipic.web.execution.dto.GenericResult;
import at.tugraz.hidipic.web.execution.dto.ParamResult;
import at.tugraz.hidipic.web.execution.util.ExecutionUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.stereotype.Component;
import weka.classifiers.Evaluation;
import weka.classifiers.trees.J48;
import weka.core.Instances;
import weka.core.converters.ConverterUtils;

/**
 *
 * @author mario
 */
@Component
public class C45Impl extends DefaultMethodImpl {

    @Override
    public void run(Map<String, Object> data) {
        try {
            List<GenericResult> outputData = new ArrayList<GenericResult>();
            Map<String, String> parameters = (Map<String, String>) data.get("parameters");
            Map<String, String> inputDataStrings = (Map<String, String>) data.get("inputData");
            //get inputfiles
            boolean train = false;
            boolean test = false;
            File trainFile = null;
            File testFile = null;
            for (String s : inputDataStrings.keySet()) {
                String ss = inputDataStrings.get(s);
                if (s.equals("train")) {
                    train = true;
                    trainFile = getFile(ss);
                }
                if (s.equals("test")) {
                    test = true;
                    testFile = getFile(ss);
                }
            }
            if (trainFile == null || testFile == null || !test || !train) {
                fireErrorEvent("There was an error with the input files for C45.");
                return;
            }
            // set specified parameters
            boolean unpruned = true;
            float confFactor = 0.25f;
            for (String p : parameters.keySet()) {
                if (p.equals("pruning")) {
                    String s = parameters.get(p);
                    if (s != null && (s.equals("n") || s.equals("y"))) {
                        if (s.equals("y")) {
                            unpruned = false;
                        }
                    }
                }
                if (p.equals("confidencethreshold")) {
                    String s = parameters.get(p);
                    if (s != null && NumberUtils.isNumber(s)) {
                        float f = Float.parseFloat(s);
                        if (NumberUtils.compare(f, 0.0f) == 1 && NumberUtils.compare(f, 1.0f) == -1) {
                            confFactor = f;
                        }
                    }
                }
            }
            fireStartEvent("C45 Execution started.");
            // start building the classifier
            ConverterUtils.DataSource sourceTrain = new ConverterUtils.DataSource(trainFile.getAbsolutePath());
            ConverterUtils.DataSource sourceTest = new ConverterUtils.DataSource(testFile.getAbsolutePath());
            Instances dataTrain = sourceTrain.getDataSet();
            Instances dataTest = sourceTest.getDataSet();
            if (dataTrain.classIndex() == -1) {
                dataTrain.setClassIndex(dataTrain.numAttributes() - 1);
            }
            if (dataTest.classIndex() == -1) {
                dataTest.setClassIndex(dataTest.numAttributes() - 1);
            }
            J48 cls = new J48();
            cls.setConfidenceFactor(confFactor);
            cls.setUnpruned(unpruned);
            // train classifier with training set
            cls.buildClassifier(dataTrain);
            // evaluate classifier on training set
            Evaluation eval = new Evaluation(dataTrain);
            eval.evaluateModel(cls, dataTest);
            // CREATE return values
            ParamResult summary = new ParamResult();
            ParamResult graph = new ParamResult();
            ParamResult matrix = new ParamResult();
            ParamResult jitJson = new ParamResult();
            summary.setName("summary");
            summary.setValue(eval.toSummaryString());
            graph.setName("graph");
            graph.setValue(cls.graph());
            matrix.setName("matrix");
            matrix.setValue(eval.toMatrixString(""));
            jitJson.setName("jitjson");
            jitJson.setValue(ExecutionUtil.getJitJson(eval));
            // add results to outputdata
            outputData.add(summary);
            outputData.add(matrix);
            outputData.add(jitJson);
            outputData.add(graph);
            // create result and finish execution
            createResult(outputData);
        } catch (Exception e) {
            LOG.error(e);
            fireErrorEvent("There was an unrecoverable error during Execution of C54.");
        }
    }
}
